﻿/*
 * @author: wizardc
 */

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.Serialization;

namespace Dou.UI
{
    /// <summary>
    /// 支持拖拽组件
    /// </summary>
    public class Draggable : MonoBehaviour, IInitializePotentialDragHandler, IBeginDragHandler, IDragHandler, IEndDragHandler
    {
        /// <summary>
        /// 第一个 Vector2 表示当前拖拽的位置（当前 RectTransform 下本地坐标），第二个 Vector2 表示拖拽的开始位置（当前 RectTransform 下本地坐标）
        /// </summary>
        [Serializable]
        public class DragEvent : UnityEvent<Vector2, Vector2, Camera> { }
        
        /// <summary>
        /// 是否直接拖拽移动自身
        /// </summary>
        public bool moveSelf = true;
        
        /// <summary>
        /// 如果拖拽可以移动自身，则会给自身添加一个Canvas同时设定Sorting的值保证自身绘制在指定的高层级上
        /// </summary>
        public int topSortingNum = 0;

        /// <summary>
        /// 开始拖拽
        /// </summary>
        public DragEvent onDragBegin;

        /// <summary>
        /// 拖拽中
        /// </summary>
        public DragEvent onDragging;

        /// <summary>
        /// 拖拽结束
        /// </summary>
        public DragEvent onDragEnd;

        private Vector2 _dragStartOffset;
        private Canvas _topCanvas;

        public void OnInitializePotentialDrag(PointerEventData eventData)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform) transform, eventData.position, eventData.pressEventCamera, out _dragStartOffset);
        }

        private Vector2 GetLocalPos(PointerEventData eventData)
        {
            RectTransformUtility.ScreenPointToLocalPointInRectangle((RectTransform) transform.parent, eventData.position, eventData.pressEventCamera, out var localPoint);
            return localPoint;
        }

        public void OnBeginDrag(PointerEventData eventData)
        {
            var pos = GetLocalPos(eventData) - _dragStartOffset;
            onDragBegin?.Invoke(pos, _dragStartOffset, eventData.pressEventCamera);
            if (moveSelf && topSortingNum > 0)
            {
                transform.localPosition = pos;
                _topCanvas = gameObject.AddComponent<Canvas>();
                _topCanvas.overrideSorting = true;
                _topCanvas.sortingOrder = topSortingNum;
            }
        }

        public void OnDrag(PointerEventData eventData)
        {
            var pos = GetLocalPos(eventData) - _dragStartOffset;
            onDragging?.Invoke(pos, _dragStartOffset, eventData.pressEventCamera);
            if (moveSelf)
            {
                transform.localPosition = pos;
            }
        }

        public void OnEndDrag(PointerEventData eventData)
        {
            var pos = GetLocalPos(eventData) - _dragStartOffset;
            onDragEnd?.Invoke(pos, _dragStartOffset, eventData.pressEventCamera);
            if (moveSelf)
            {
                transform.localPosition = pos;
                DestroyImmediate(_topCanvas);
                _topCanvas = null;
            }
        }
    }
}
